package com.plata.base.aclr.utils;

import java.io.PrintWriter;
import java.io.StringWriter;

/**
 * @author xiangshixiang
 * @version 2014/11/29
 */
public class LogTool {
    private static final String TAG = "LogTool";
    private static final String ROOT_TAG = "p2papi";

    public static final int TRACE_LEVEL = 0x01;
    public static final int INFO_LEVEL = 0x02;
    public static final int WARN_LEVEL = 0x04;
    public static final int ERROR_LEVEL = 0x08;
    public static final int FATAL_LEVEL = 0x10;
    private static int sLogLevel = TRACE_LEVEL | INFO_LEVEL | WARN_LEVEL | ERROR_LEVEL | FATAL_LEVEL;

    /**
     * Priority constant for the print method;
     */
    private static final int VERBOSE = 2;
    private static final int DEBUG = 3;
    private static final int INFO = 4;
    private static final int WARN = 5;
    private static final int ERROR = 6;

    public static final void setLogLevel(int level) {
        if (true) {
            sLogLevel = level;
        }
    }

    public static final void v(String tag, String msg) {
        if ((sLogLevel & TRACE_LEVEL) != 0) {
            print(VERBOSE, ROOT_TAG, buildLog(tag, msg, null));
        }
    }

    public static final void v(String tag, String msg, Throwable tr) {
        if ((sLogLevel & TRACE_LEVEL) != 0) {
            print(VERBOSE, ROOT_TAG, buildLog(tag, msg, tr));
        }
    }

    public static final void v(String tag, String format, Object... args) {
        v(tag, null, format, args);
    }

    public static final void v(String tag, Throwable tr, String format, Object... args) {
        if ((sLogLevel & TRACE_LEVEL) != 0) {
            print(VERBOSE, ROOT_TAG, buildLog(tag, formatString(format, args), tr));
        }
    }

    public static final void d(String tag, String msg) {
        if ((sLogLevel & TRACE_LEVEL) != 0) {
            print(DEBUG, ROOT_TAG, buildLog(tag, msg, null));
        }
    }

    public static final void d(String tag, String msg, Throwable tr) {
        if ((sLogLevel & TRACE_LEVEL) != 0) {
            print(DEBUG, ROOT_TAG, buildLog(tag, msg, tr));
        }
    }

    public static final void d(String tag, String format, Object... args) {
        d(tag, null, format, args);
    }

    public static final void d(String tag, Throwable tr, String format, Object... args) {
        if ((sLogLevel & TRACE_LEVEL) != 0) {
            print(DEBUG, ROOT_TAG, buildLog(tag, formatString(format, args), tr));
        }
    }

    public static final void i(String tag, String msg) {
        if ((sLogLevel & INFO_LEVEL) != 0) {
            print(INFO, ROOT_TAG, buildLog(tag, msg, null));
        }
    }

    public static final void i(String tag, String msg, Throwable tr) {
        if ((sLogLevel & INFO_LEVEL) != 0) {
            print(INFO, ROOT_TAG, buildLog(tag, msg, tr));
        }
    }

    public static final void i(String tag, String format, Object... args) {
        i(tag, null, format, args);
    }

    public static final void i(String tag, Throwable tr, String format, Object... args) {
        if ((sLogLevel & INFO_LEVEL) != 0) {
            print(INFO, ROOT_TAG, buildLog(tag, formatString(format, args), tr));
        }
    }

    public static final void w(String tag, String msg) {
        if ((sLogLevel & WARN_LEVEL) != 0) {
            print(WARN, ROOT_TAG, buildLog(tag, msg, null));
        }
    }

    public static final void w(String tag, String msg, Throwable tr) {
        if ((sLogLevel & WARN_LEVEL) != 0) {
            print(WARN, ROOT_TAG, buildLog(tag, msg, tr));
        }
    }

    public static final void w(String tag, String format, Object... args) {
        w(tag, null, format, args);
    }

    public static final void w(String tag, Throwable tr, String format, Object... args) {
        if ((sLogLevel & WARN_LEVEL) != 0) {
            print(WARN, ROOT_TAG, buildLog(tag, formatString(format, args), tr));
        }
    }

    public static final void e(String tag, String msg) {
        if ((sLogLevel & ERROR_LEVEL) != 0) {
            print(ERROR, ROOT_TAG, buildLog(tag, msg, null));
        }
    }

    public static final void e(String tag, String msg, Throwable tr) {
        if ((sLogLevel & ERROR_LEVEL) != 0) {
            print(ERROR, ROOT_TAG, buildLog(tag, msg, tr));
        }
    }

    public static final void e(String tag, String format, Object... args) {
        e(tag, null, format, args);
    }

    public static final void e(String tag, Throwable tr, String format, Object... args) {
        if ((sLogLevel & ERROR_LEVEL) != 0) {
            print(ERROR, ROOT_TAG, buildLog(tag, formatString(format, args), tr));
        }
    }

    private static final void print(int priority, String tag, String msg) {
        android.util.Log.println(priority, tag, msg);
    }

    private static final String buildLog(String tag, String msg, Throwable tr) {
        if (tr != null) {
            if (StringUtils.isEmpty(msg)) {
                msg = getStackTraceString(tr);
            } else {
                msg = msg + '\n' + getStackTraceString(tr);
            }
        }
        return new StringBuffer().append("[").append(tag).append("] ").append(msg).toString();
    }

    private static String formatString(String format, Object... args) {
        try {
            return String.format(format.replaceAll("%d", "%s").replaceAll("%f", "%s"), args);
        } catch (Exception e) {
            e(TAG, "formatString failed. " + e.toString());
            if (args != null) {
                for (Object arg : args) {
                    format += ", " + arg;
                }
            }
            return format;
        }
    }

    /**
     * Handy function to get a loggable stack trace from a Throwable
     *
     * @param tr An exception to log
     */
    public static String getStackTraceString(Throwable tr) {
        if (tr == null) {
            return "";
        }

        Throwable t = tr;
        while (t != null) {
            t = t.getCause();
        }

        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw, false);
        tr.printStackTrace(pw);
        pw.flush();
        return sw.toString();
    }
}
